package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.message.ArticleForEsConstants;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.feigns.article.ArticleFeign;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.constants.wemedia.WemediaConstants;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.utils.threadlocal.WmThreadLocalUtils;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vos.WmNewsVo;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmMaterialService;
import com.heima.wemedia.service.WmNewsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class WmNewsServiceimpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
    String webSite;

    @Resource
    private KafkaTemplate kafkaTemplate;

    @Resource
    WmNewsMaterialMapper wmNewsMaterialMapper;

    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //参数校验
        if (dto == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //分页参数校验
        dto.checkParam();
        //判断用户是否登录
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }
        //封装分页条件
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //封装查询条件
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        //如果有文章标题，按照文章标题模糊查询
        if (StringUtils.isNoneBlank(dto.getKeyword())) {
            queryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //如果有频道信息，按照频道ID查询
        if (dto.getChannelId() != null) {
            queryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //如果有文章状态，按照状态信息进行查询
        if (dto.getStatus() != null) {
            queryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //如果开始时间，结束时间不为空按照时间区间查询
        if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            queryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }
        //按照登录用户ID去查询
        queryWrapper.eq(WmNews::getUserId, user.getId());
        //按照创建时间降序
        queryWrapper.orderByDesc(WmNews::getCreatedTime);
        //进行分页查询
        IPage<WmNews> pageRes = this.page(page, queryWrapper);

        //返回数据封装
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) pageRes.getTotal());

        pageResponseResult.setData(pageRes.getRecords());
        //分页查询，返回结果添加图片访问前缀
        pageResponseResult.setHost(webSite);

        return pageResponseResult;
    }

    /**
     * 自媒体文章发布
     *
     * @param wmNewsDto
     * @param isSubmit  是否为提交 1 为提交 0为草稿
     * @return
     */
    @Override
    @Transactional
    public ResponseResult saveNews(WmNewsDto wmNewsDto, Short isSubmit) {
        //参数校验
        if (wmNewsDto.getContent() == null || StringUtils.isBlank(wmNewsDto.getContent())) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        WmUser user = WmThreadLocalUtils.getUser();

        if (user == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }

        //复制属性
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(wmNewsDto, wmNews);

        if (user.getId() != null) {
            wmNews.setUserId(user.getId());
        }

        //如果文章布局是自动，需要设置为null
        if (wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }

        //把字符串转成对象
        List<Map> contents = JSON.parseArray(wmNews.getContent(), Map.class);
        //取出图片
        List<String> images = parseContentImages(contents);
        //封装图片数量类型
        if (WemediaConstants.WM_NEWS_TYPE_AUTO.equals(wmNewsDto.getType()) || wmNewsDto.getType() == null) {
            setTypeByImage(images, wmNews);
        }

        if (wmNewsDto.getType() != null && (!wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO))) {
            setTypeByImage(wmNewsDto.getImages(), wmNews);
        }

        //保存或修改文章
        if (wmNewsDto.getId() != null) {
            // 如果有id修改文章，先删除所有素材关联关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNewsDto.getId()));

            this.updateById(wmNews);
        } else {

            this.save(wmNews);
        }

        // 保存素材和文章关系，抽取一个独立方法执行关联操作，原因当前方法可以复用
        saveRelativeInfo(wmNews, isSubmit);

        // 4 发消息给admin审核文章
        Map map = new HashMap();
        map.put("wmNewsId", wmNews.getId());
        kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));

        return ResponseResult.okResult();
    }


    private void setTypeByImage(List<String> imageUrl, WmNews wmNews) {
        String imagStr = imageListToStr(imageUrl, webSite);
        wmNews.setImages(imagStr);
        wmNews.setCreatedTime(new Date());
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable(WemediaConstants.WM_NEWS_UPENABLE); // 上架

        if (imageUrl != null && imageUrl.size() > 0) {
            if (imageUrl.size() > 2) {
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
            } else {
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
            }
        } else {
            wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
        }


    }

    @Resource
    WmMaterialService wmMaterialService;

    //把图片集合封装成String字符串
    private String imageListToStr(List<String> images, String webSite) {
        return images.stream().map(url -> url.replace(webSite, "")).collect(Collectors.joining(","));
    }

    private void saveRelativeInfo(WmNews wmNews, Short isSubmit) {
        //把字符串转成对象
        List<Map> contents = JSON.parseArray(wmNews.getContent(), Map.class);
        //取出图片
        List<String> images = parseContentImages(contents);

        //创建存储图片id的集合
        ArrayList<Integer> urlId = new ArrayList<>();
        if (images != null && images.size() > 0) {
            //根据图片获取图片id
            for (String image : images) {
                WmMaterial wmMaterial = wmMaterialService.getOne(Wrappers.<WmMaterial>lambdaQuery().eq(WmMaterial::getUrl, image));
                urlId.add(wmMaterial.getId());
            }
        }
        // 保存素材和文章关系
        wmNewsMaterialMapper.saveRelations(urlId, wmNews.getId(), isSubmit);
    }

    private List<String> parseContentImages(List<Map> contents) {
        return contents.stream() // 流式处理
                .filter(map -> map.get("type").equals("image")) // 过滤是图片
                .map(map -> (String) map.get("value")) // 映射处理->获取图片url
                .map(imageUrl -> imageUrl.replace(webSite, "")) // 映射处理->替换前缀路径
                .collect(Collectors.toList()); // 将图片收集到一个图片集合中
    }


    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //参数校验
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        WmUser user = WmThreadLocalUtils.getUser();
        //判断当前用户是否登录
        if (user == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }

        //查询
        WmNews wmNews = this.getOne(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getId, id).eq(WmNews::getUserId, user.getId()));

        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //返回结果
        ResponseResult result = ResponseResult.okResult(wmNews);

        result.setHost(webSite);

        return result;
    }

    @Override
    public ResponseResult delNews(Integer id) {
        //参数校验
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        WmUser user = WmThreadLocalUtils.getUser();
        //判断当前用户是否登录
        if (user == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询数据是否存在
        WmNews wmNews = this.getById(id);
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //当文章状态为9(已发布)且已上架则不能删除文章，下架状态可以删除，如果是其他状态可以删除
        if (wmNews.getStatus().equals(WemediaConstants.WM_NEWS_PUBLISH_STATUS) && wmNews.getEnable().equals(WemediaConstants.WM_NEWS_UPENABLE)) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "请先下架后再进行此操作");
        }
        //删除文章之前需要先把素材与文章的关系删除掉
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, id));
        //删除文章
        this.remove(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getId, id).eq(WmNews::getUserId, user.getId()));
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //参数校验
        if (dto == null && dto.getId() == null && dto.getStatus() == null && dto.getEnable() == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        WmUser user = WmThreadLocalUtils.getUser();
        //判断当前用户是否登录
        if (user == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 当前已经发布（状态为9）的文章可以上架（enable = 1），也可以下架（enable = 0）
        if (!dto.getStatus().equals(WemediaConstants.WM_NEWS_PUBLISH_STATUS)) {
            throw new CustomException(AppHttpCodeEnum.NO_OPERATOR_AUTH, "该文章并没有发布");
        }

        //.........................................根据文章id查询文章是否存在
        WmNews wmNews = this.getById(dto.getId());
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //进行修改
        this.update(Wrappers.<WmNews>lambdaUpdate().set(WmNews::getEnable, dto.getEnable()).eq(WmNews::getUserId, user.getId()));

        //发送mq消息通知app端
        Map<String, Object> mesMap = new HashMap<>();
        mesMap.put("enable", dto.getEnable());
        mesMap.put("articleId", dto.getId());
        kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, JSON.toJSONString(mesMap));


        //kafka发送消息同步es数据
        Map map = new HashMap();
        map.put("articleId", wmNews.getArticleId());
        if (dto.getEnable().intValue() == 0) {
            kafkaTemplate.send(ArticleForEsConstants.ARTICLE_ELASTICSEARCH_DELETE, JSON.toJSONString(map));
        } else {
            kafkaTemplate.send(ArticleForEsConstants.ARTICLE_ELASTICSEARCH_ADD, JSON.toJSONString(map));
            return ResponseResult.okResult();
        }

        return ResponseResult.okResult();
    }

    @Override
    public List<Integer> findRelease() {
        //查询状态为通过且未发布的文章，并且发布时间小于等于当前时间的
        List<WmNews> wmNewsList = this.list(Wrappers.<WmNews>lambdaQuery().in(WmNews::getStatus, 4, 8).le(WmNews::getPublishTime, new Date()));
        //取出所以文章的id
        return wmNewsList.stream().map(WmNews::getId).collect(Collectors.toList());

    }

    @Resource
    WmNewsMapper wmNewsMapper;

    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        //分页参数校验
        dto.checkParam();
        //记录当前页
        int currentPage = dto.getPage();
        //设置起始页
        dto.setPage((dto.getPage() - 1) * dto.getSize());

        if (StringUtils.isNotBlank(dto.getTitle())) {
            dto.setTitle("%" + dto.getTitle() + "%");
        }

        //查询文章列表
        List<WmNewsVo> wmNewsList = wmNewsMapper.findListAndPage(dto);
        //查询总记录数
        long count = wmNewsMapper.findListCount(dto);
        //封装返回结果
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), currentPage);

        pageResponseResult.setData(wmNewsList);

        pageResponseResult.setHost(webSite);
        return pageResponseResult;
    }

    @Resource
    WmUserMapper wmUserMapper;

    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //参数校验
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //根据id查询文章数据
        WmNews wmNews = this.getById(id);
        //判断文章是否存着
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "文章信息不存在");
        }

        //查询用户
        WmUser wmUser = wmUserMapper.selectById(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getId, wmNews.getUserId()));

        //判断用户是否存在
        if (wmUser == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "文章的作者信息不存在");
        }

        //4.封装返回信息
        WmNewsVo wmNewsVo = new WmNewsVo();

        BeanUtils.copyProperties(wmNews, wmNewsVo);

        wmNewsVo.setAuthorName(wmUser.getName());

        ResponseResult responseResult = ResponseResult.okResult(wmNewsVo);

        responseResult.setHost(webSite);

        return responseResult;

    }

    @Override
    public ResponseResult updateStatus(Short status, NewsAuthDto dto) {
        //参数校验
        if (dto == null || dto.getId() == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //查询文章
        WmNews wmNews = this.getById(dto.getId());
        //判断文章是否存在
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }
        //修改文章状态
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(WmNews::getStatus, dto.getStatus());

        queryWrapper.eq(WmNews::getId, dto.getId());

        if (StringUtils.isNoneBlank(dto.getMsg())) {
            queryWrapper.eq(WmNews::getReason, dto.getMsg());
        }
        this.update(queryWrapper);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}
